#-*- mode: perl; coding:utf-8 -*-
#!/usr/local/bin/perl
# ===
# TITLE: fsd.pl
# CATEGORY: SOURCE
# ■Abstact
#
#    Translate text document -> html( & SVG,dot...)
#
#    features
#      - extract document form text file(.txt) or source code(now .pl .cpp .h) 
#      - Wiki like syntax
#      - use internal link(Wiki like)
#      - make Sequence Chart(SVG), State Chart (use Graphviz) and so on.
#      - make table and graph.  
#      - attach files 
#      - color source code : (use google-code-prettify) 
#
# ■TODO
# - 一時的ドキュメントの生成，参照
# - TAGによる分類
# - 日本語対応(出力ファイル名のエンコード)
# - 環境変数によるドキュメントフォルダへの指定
# - ファイルの削除
# - C/C++ のコメントからドキュメントを抽出する
# - 添付ファイル(attach)のリンクや貼り付け（イメージ）
# - 見出しのリンク化
# - 画像（自動生成）のファイル名管理（いまの所暫定）
# - 文書の管理（自動更新）
# - flow chart
# - indexのJavascript化(アコーディオンメニュー等)
# ===

# use Packages (tested Active perl)
use utf8;
use Encode;
use WildCard;                                               # for ActivePerl only
use FindBin;                                                # find script's dir
use File::Copy;                                             # copy
use File::Copy::Recursive qw(dircopy);                      # dircopy
use File::Find;                                             # 
use File::Path;                                             # rmtree
use lib "$FindBin::Bin";                                    # 
use Storable qw(nstore retrieve);                           # Storable
use Data::UUID;                                             # install Data-UUID
use Data::Dumper;                                           # debug

# Main
$Debug = 1;                                                 # 0:release 1:debug

# system coding system 
$InCodingSystem{"TXT"} = "shiftjis";   # for .txt (Now Japan/Windows)
$InCodingSystem{"CPP"} = "shiftjis";   # for .cpp .h (Now Japan/Windows)
$InCodingSystem{"PL"}  = "utf8";       # for .pl (NowUTF-8)

# Settings
#   Header pattern
$Heading1 = "■";
$Heading2 = "◆";
$Heading3 = "・";
$Heading4 = "【";

# Header Prefix 
$Heading1Prefix = "■ ";
$Heading2Prefix = "◆ ";
$Heading3Prefix = "";
$Heading4Prefix = "【";

#Code(.cpp/.h/.pl) comment fsd block bigen & end Separator
$FsdBlockSep = "===";                                       

# Output folder
$DocDirName = "doc";                                        # document folder
$ImageDirName = "Images";                                   # images folder 
$IndexFileName = "Index.html";                              # index.html
$UseFrame = "contents";

# temp output folder (-t option)
$TempDir = "c:/temp/fsd_temp";                              # とりあえず
 
#attach file ext(use small latters) 1 : inline image 2:reference
%AttachExt = ("png", 1,"jpg", 1,"gif", 1,
              "doc", 2,"ppt", 2,"xls", 2,"pdf", 2);

#browser command line paramator
#$Browser = "\"C:\\Program Files\\Mozilla Firefox\\firefox.exe\" -url";
#$Browser = "\"C:\Documents and Settings\Miura\Local Settings\Application Data\Google\Chrome\Application\chrome.exe\"
$Browser = "safari";

#GoogleCodePrettify
$UseGoogleCodePrettify = 1;

#debug print coding system
binmode STDOUT, ':encoding(cp932)';                         # output coding system(New Japan/Windows)
binmode STDERR, ':encoding(cp932)';                         # error coding system(New Japan/Windows)

#internal packages
require "sqlib.pm";                                         # Sequence/Trace
require "stlib.pm";                                         # State Chart 
require "cllib.pm";                                         # Class Chart 
require "dumplib.pm";                                       # Object Chart from Dump 

# command line check
if (! @ARGV) {                                              # if no paramater,show usage
    print <<END_OF_DATA;
usage : fsd [-d doc_folder | -t] [FILENAME | DIRECTORY]  ...
  text documentよりHTML文書を作成する．
  FILENAMEで指定したファイルあるいは，DIRECTORY以下のファイルを処理する．
  ドキュメントはdoc_folder以下に作成される．(未指定の場合カレントディレクトリ
  以下にdocフォルダを作成)
options :
  -d doc_folder  ドキュメントフォルダを指定
  -t  一時フォルダに出力し，ブラウザを起動
END_OF_DATA
    exit;
}

#Current Working Directory
$cwd1 = `cd`;
$cwd1 =~ s/^[A-Za-z]://;    # remove drive name for dos
$cwd1 =~ tr/\\/\//;         # change \ to / for dos
$cwd1 =~ s/\s*$//;          # remove last spaces 

$RunBrowser = 0;

#-d option as Output Directory
if ($ARGV[0] eq "-d") {                                     # -d option?
    shift(@ARGV);
    $DocDir = $ARGV[0];
    $DocDir =~ s/\"//;
    $DocDir =~ tr/\\/\//;
    $DocDir =~ s/\/$//;
    shift(@ARGV);
} elsif ($ARGV[0] eq "-t") {                                # -t option?
    $DocDir = $TempDir;                                     # temp
    $RunBrowser = 1;
    if (-d $DocDir || -f $DocDir) {                         # if exist
        rmtree([$DocDir]);                                  # remove all
    }
    if (-d $DocDir || -f $DocDir) {                         # if exist
        die "cannot remove $DocDir\n";
    }
} else {
    $DocDir = $ENV{"FSD_OUT"};
    if (! $DocDir) {
        # Default is "cwd/doc"; 
        $DocDir = "$cwd1/$DocDirName";
    }
}

$Debug && print "Documents output to $DocDir\n";

#Make Document Directory if not exist
if (!(-d $DocDir)) {
    mkdir ($DocDir, 0755) || die "cannot create $DocDir";
    copy("$FindBin::Bin/DocStyle.css", "$DocDir/DocStyle.css"); 
    copy("$FindBin::Bin/Frame.html", "$DocDir/Frame.html");
    # for google-code-prettify
    dircopy("$FindBin::Bin/js", "$DocDir/js");                 
}

#Make Image Sub Directory if not exist
$ImageDir = "$DocDir/$ImageDirName";
if (!(-d $ImageDir)) {
    mkdir ($ImageDir, 0755) || die "cannot create $ImageDir\n";
}

#Make Link Sub Directory if not exist
$LinkDir = "$DocDir/Link";
if (!(-d $LinkDir)) {
    mkdir ($LinkDir, 0755) || die "cannot create $ImageDir\n";
}

#Make Attach Sub Directory if not exist
$AttachDir = "$DocDir/Attach";
if (!(-d $AttachDir)) {
    mkdir ($AttachDir, 0755) || die "cannot create $AttachDir\n";
}

#restore document database
&LoadDocDB();

#do all file and find from directories
find(\&DoAllFiles, @ARGV);

# Output Index File
&OutputIndex();

# Save Document Data
&SaveDocDB();                                               # DocDB保存

if ($RunBrowser) {
    my $DocDirDos = $DocDir;
    $DocDirDos =~ s/\//\\/g;
    print "$Browser $DocDirDos\\Frame.html";
    exec "$Browser $DocDirDos\\Frame.html";
}
exit 0;                                                     # end of script

#DoAllFiles call by find
sub DoAllFiles {
    my ($path) = $File::Find::dir;
    my ($file) = $_;
    my ($fullpath) = $File::Find::name;
    if ($path eq ".\\") {
        $path = ".";
    } elsif ($path !~ /^\// ) {
        $path = $cwd1 . "/" . $path;
    }
    if ($file =~ /\.[Tt][Xx][Tt]$/) {                       # .txt -> document
        &doc2html($path, $file);
    } elsif ($file =~ /\.[Hh]/) {                           # .h -> class chart
        #not implemented
    } elsif ($file =~ /\.[Cc][Pp][Pp]/) {                   # .cpp -
        &doc2html($path, $file);
    } elsif ($file =~ /\.[Pp][Ll]/) {                       # .pl -
        &doc2html($path, $file);
    } elsif (IsAttachFile($file)) {                         # Attach files
        # if it has ext in $AttachExt, copy to $AttachDir 
        $Debug && print "add attach file $name\n";
        copy($fullpath, "$AttachDir/$name");
    }
}

#############################################################################
#      Text -> HTML
#############################################################################
sub doc2html {
    my ($dir, $name) = @_;

	&InitializeDoc();
    &OpenSource($name);                                     # 
    my ($timeStamp) = &getFileTimeStamp($name);             # file's TimeStamp
	printf("PROCESSING FILE:%s\n", $name);                  # 
	$OutFile = $name;                                       # 
	$OutFile =~ s/([^\.]*)$/html/;                          # 拡張子 ⇒ .html
	open(OUT, ">:utf8", "$DocDir/$OutFile") || die "Can't open output file"; 
    &AddOutputFile("$DocDir/$OutFile");
    my $default_title = $name;
	$default_title =~ s/(\.[^\.]*)$//;                      # 拡張子を取る
    &AddProperty("FILEPATH", $OutFile);
    &AddProperty("TITLE", $default_title);
    &AddProperty("TIMESTAMP", $timeStamp);
    
    # parse prpperty
	while($_= &ReadSource()) {
		if ($_ =~ /^\s*([A-Za-z0-9\_]+)\:(.*)$/) {
			&AddProperty($1, $2);
		} elsif ($_ !~ /^\s*$/) {
			last;
		}
	}
    &MakeLinkTarget($g_DocProperty{"TITLE"},
                    "$OutFile", 0,
                    $g_DocProperty{"CATEGORY"},
                    $g_DocProperty{"TIMESTAMP"});
    &AddDocument();
    &DocMain();

    &CloseSource();
	close(OUT);
    my(@outfiles) = @g_DocOutFiles;
    $g_Documents{$g_DocProperty{"UUID"}}[5] = \@outfiles;

    if ($g_flagAddUuid) {
        &writeFileUUID("$dir/$name", $g_DocProperty{"UUID"}, "shiftjis")
    }
}

# タイムスタンプ取得
sub getFileTimeStamp {
    my ($file) = @_;  
    my (@fstat) = stat($file);
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($fstat[9]);
    my ($timeStamp) = sprintf("%04d/%02d/%02d %02d:%02d",$year+1900,$mon+1,$mday,$hour,$min); 
    return $timeStamp;
}

# ファイルにUUIDを書き込む
# todo:backupをとる
sub writeFileUUID {
    my ($file, $uuid, $code) = @_;
    if ($code) {
        $code = "shiftjis";
    }
    $Debug && print "write uuid $file $uuid $code\n";
    open WF, "<:encoding($code)", "$file" || return;
    my @lines = <WF>;
    close(WF);
    my $line;
    my $done = 0;
    open WF, ">:encoding($code)", "$file" || return;
    foreach $line (@lines) {
        if (!$done && $line =~ /^(\s*UUID\:)/) {
            print WF "$1 $uuid\n";
            $done = 1;
        } else {
            print WF $line;
        }
    }
    close(WF);
    print "done\n";
}

sub AddProperty {
    my ($name, $value) = @_;
	$g_DocProperty{$name} = $value;
}

sub AddOutputFile {
    my ($file) = @_;
    push(@g_DocOutFiles, $file);
}

sub AddDocument {
    my $path, $title, $category, $timeStamp,$uuid;
    $path = $g_DocProperty{"FILEPATH"};
    $title = $g_DocProperty{"TITLE"};
    $category = $g_DocProperty{"CATEGORY"};
    $timeStamp = $g_DocProperty{"TIMESTAMP"};
    $uuid = $g_DocProperty{"UUID"};
    if ($uuid =~ /^\s*$/) {                                      # UUIDが空白
        my($ug)    = new Data::UUID;
        $uuid = $ug->create_str();
        $g_DocProperty{"UUID"} = $uuid;
        $g_flagAddUuid = 1;                                 # uuidを生成したのでファイルに書き込む
    } elsif ($uuid eq "None") {                             # UUID未定義（ファイルに書き込みなし）
        $uuid = $path;
        $g_DocProperty{"UUID"} = $uuid;
    }
    $Debug && print " - AddDocument[$uuid] $category,$title\n";
    if ($g_Documents{$uuid}) {                              # すでにドキュメント存在する場合
        &DeleteDoc($uuid);
    }
    $g_Documents{$uuid} = [$category, $title, "TOP", $path, $timeStamp, []];
    push(@g_DocDB, [$category,$title,"TOP",$path]);
}

sub AddDocumentIndex {
    my ($level, $index) = @_;
    my $path, $title, $category, $timeStamp,$uuid;
    $path = $g_DocProperty{"FILEPATH"};
    $title = $g_DocProperty{"TITLE"};
    $category = $g_DocProperty{"CATEGORY"};
    $timeStamp = $g_DocProperty{"TIMESTAMP"};
    $uuid = $g_DocProperty{"UUID"};
    
    $Debug && print "・AddDocumentIndex $level, $index\n";
    push(@g_DocDB, [$category,$title,$index,$path]);
}


#Output index to "index.html" 
sub OutputIndex {
    my @index;

    print "**OutputIndex\n";

#Create Index
    open(INDEX, ">:utf8", "$DocDir/$IndexFileName") || die "Can't create index file";
    print INDEX <<END_OF_DATA;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<HTML lang="ja">
<HEAD>
  <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <LINK rel="stylesheet" href="DocStyle.css">
  <TITLE>Document</TITLE>
</HEAD>
<BODY>

END_OF_DATA

    @index = sort{$$a[0] cmp $$b[0] or $$a[1] cmp $$b[1] or $$a[2] cmp $$b[2]} @g_DocDB;
    my $last_category,$last_title;
    print INDEX "<ul class=category>\n";
    my ($b_openTitle) = 0;
    my ($b_openItem) = 0;
    foreach $entry (@index) {
        my ($category,$title,$item,$path) = @$entry;
        $Debug && print "OutIndex $category,$title,$item\n";
        if ($title ne $last_title) {
            if ($b_openItem) {
                print INDEX "    </ul>\n";
                $b_openItem = 0;
            }
            if ($category ne $last_category) {
                if ($b_openTitle) {
                    print INDEX "  </ul>\n";
                    $b_openTitle = 0;
                }
                print INDEX "  <li><A>$category</A></li>\n";
                $last_category = $category;
            }
            if (! $b_openTitle) {
                print INDEX "  <ul class=title>\n";
                $b_openTitle = 1;
            }
            my $label,$url;
            $label = &HTMLText($title);
            $url = &HTMLText($path);
            if ($UseFrame) {
                print INDEX "    <li><A HREF=\"$url\" target=\"$UseFrame\">$label</A></li>\n";
            } else {
                print INDEX "    <li><A HREF=\"$url\">$label</A></li>\n";
            }
            $last_title = $title;
        }
        if ($item ne "TOP") {
            if (! $b_openItem) {
                print INDEX "    <ul class=item>\n";
                $b_openItem = 1;
            }
            my $label,$url;
            $label = &HTMLText($item);
            $url = &HTMLText("$path#$item");
            if ($UseFrame) {
                print INDEX "      <li><A HREF=\"$url\" target=\"$UseFrame\">$label</A></li>\n";
            } else {
                print INDEX "      <li><A HREF=\"$url\">$label</A></li>\n";
            }
        }
    }
    if ($b_openItem) {
        print INDEX "    </ul>\n";
        $b_openItem = 0;
    }
    print INDEX <<END_OF_DATA;
    </ul>
</ul>
</BODY>
</HTML>
END_OF_DATA

}

#Main部分
sub DocMain {
	&DocHeader();
    &EnterParagraph();
	while($_ = &ReadSource()) {
        if ($_ =~ /^\s*$Heading1(.*)$/) {                    # 見出し処理1
            print "debug: $Heading1 $1\n";
			&CloseList();
            &ExitParagraph();
			&MakeHeading(2, $Heading1Prefix, $1);
        } elsif ($_ =~ /^\s*$Heading2(.*)$/) {               # 見出し処理2
			&CloseList();
            &ExitParagraph();
			&MakeHeading(3, $Heading2Prefix, $1);
        } elsif ($_ =~ /^\s*$Heading3(.*)$/) {               # 見出し処理2
			&CloseList();
            &ExitParagraph();
			&MakeHeading(4, $Heading3Prefix, $1);
        } elsif ($_ =~ /^\s*$Heading4(.*)$/) {               # 見出し処理2
			&CloseList();
            &ExitParagraph();
			&MakeHeading(5, $Heading4Prefix, $1);
        } elsif ($_ =~ /^\s*(.*)\s*⇒\s*(.*)$/) {                # Link
            &AddParagraphRaw(&MakeAnchor($1, $2));
        } elsif ($_ =~ /^\s*((http|file|https)\:.*)$/) {         # Link2
			&AddParagraphRaw(&MakeAnchor($1, $1));
        } elsif ($_ =~ /^\s*\[\[(.*)\]\]/) {                     # Link3
            my ($link) = &MakeLink($1);
            print OUT $link;
        } elsif ($_ =~ /\*\*see\s+(.*\.\w+)/) {                  # Attach File
			&MakeAttachFile($1);
        } elsif ($_ =~ /^(\s*)\-([^-].*)$/) {                    # -List(No#)
            &ExitParagraph();
			&MakeList($1, $2, 0);
        } elsif ($_ =~ /^(\s*)\+(.*)$/) {                        # +List(#)
            &ExitParagraph();
			&MakeList($1, $2, 1);
        } elsif ($_ =~ /^(\s*)\[(.*)\]\s*$/) {                   # [ ]List
            &ExitParagraph();
			&MakeList($1, $2, 2);
        } elsif ($_ =~ /^\-\-begin code/) {                      # CODE
            &ExitParagraph();
			&DocCode();
        } elsif ($_ =~ /^\-\-begin csv/) {                       # CSV(Table)
            &ExitParagraph();
			&DocTable(1);            
        } elsif ($_ =~ /^\*\*table/) {                           # Table(Tab)
            &ExitParagraph();
            &DocTable2();
        } elsif ($_ =~ /^\-\-begin bar/) {                       # bar graph
            &ExitParagraph();
			&DocBar(1);
        } elsif ($_ =~ /^\-\-begin sequence/) {                  # Sequence
            &ExitParagraph();
			&DocSequence();
        } elsif ($_ =~ /^\-\-begin trace/) {                     # Trace
            &ExitParagraph();
			&DocTrace();
        } elsif ($_ =~ /^\-\-begin state/) {                     # State Chart
            &ExitParagraph();
			&DocState();
        } elsif ($_ =~ /^\-\-begin class/) {                     # Class Chart
            &ExitParagraph();
			&DocClass();
        } elsif ($_ =~ /^\-\-begin dump/) {                      # dump
            &ExitParagraph();
			&DocDump();
        } elsif ($_ =~ /^\s*$/) {                                # Empty Line
            &ExitParagraph();
			&CloseList();
		} else {                                                 # Other Line
            &AddParagraph($_);
		}
	}                                                            # end of loop
    &ExitParagraph();
    &CloseList();
	&DocFooter();
}

sub DocHeader {
	my ($title) = &HTMLText($g_DocProperty{"TITLE"});
    my ($timeStamp) = &HTMLText($g_DocProperty{"TIMESTAMP"});

    if ($UseGoogleCodePrettify) {
        print OUT <<END_OF_DATA;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<HTML lang="ja">
<HEAD>
  <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <LINK rel="stylesheet" href="DocStyle.css">
  <LINK rel="stylesheet" href="js/prettify.css">
  <script type="text/javascript" src="js/prettify.js"></script>
  <TITLE>$title</TITLE>
</HEAD>

<BODY onload="prettyPrint()">
  <H1>$title</H1>
  <P class="docinfo">last update $timeStamp</P>
  <HR>
END_OF_DATA

    } else {
        print OUT <<END_OF_DATA;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<HTML lang="ja">
<HEAD>
  <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <LINK rel="stylesheet" href="DocStyle.css">
  <TITLE>$title</TITLE>
</HEAD>

<BODY>
  <H1>$title</H1>
  <P class="docinfo">last update $timeStamp</P>
  <HR>
END_OF_DATA
    }

}

sub DocFooter {
    print OUT <<END_OF_DATA;
  <HR>
  <A HREF="#TOP">TOP</A><BR>
</BODY>
</HTML>

END_OF_DATA
}

# 見出し
sub MakeHeading {
	my ($Level, $Prefix, $Label) = @_;
	$Label = &HTMLText($Label);

    # 目次情報追加
    &AddDocumentIndex($Level,$Label);

	print OUT <<END_OF_DATA;

  <H$Level ID="$Label">$Prefix$Label</H$Level>

END_OF_DATA
}

#Anchor
sub MakeAnchor {
	my ($Label, $URL) = @_;
	$Label = &HTMLText($Label);
	$URL = &HTMLText($URL);
	return "<A HREF=\"$URL\" TARGET=\"_top\">$Label</A>";
}

#Image
sub MakeImage {
	local($URL) = @_;
	$URL = &HTMLText($URL);
	print OUT <<END_OF_DATA;
    <BR>
    <IMG SRC="$URL"><BR>
END_OF_DATA
}

#SVG Embedding
sub EmbedSVG {
	local($URL, $x, $y) = @_;
	$URL = &HTMLText($URL);
	print OUT <<END_OF_DATA;
    <BR>
<EMBED pluginspage="http://www.adobe.com/svg/viewer/install/main.html" 
      src="$URL" width=$x height=$y type="image/svg+xml"><BR>
END_OF_DATA
}

#List (depend on indent level)
sub MakeList {
	my ($indent, $item, $type) = @_;
	my ($nIndent) = length($indent);
    $g_IsDefineData = 0;

	$item = &HTMLText($item);

    # Open 
	if ((! @g_aListIndent) || 
        $nIndent > $g_aListIndent[$#g_aListIndent]) {
		push(@g_aListOrder, $type);
        push(@g_aListIndent, $nIndent);
        if ($type == 0) {
            print OUT "<UL>\n";
        } elsif ($type == 1) {
            print OUT "<OL>\n";
        } elsif ($type == 2) {
            print OUT "<DL>\n";
        }
	} 
    # Close 
    while ($nIndent < $g_aListIndent[$#g_aListIndent]) {
        pop(@g_aListIndent);
        my ($close_type) = pop(@g_aListOrder);
        if ($close_type == 0) {
            print OUT "</UL>\n";
        } elsif ($close_type == 1) {
            print OUT "</OL>\n";
        } elsif ($close_type == 2) {
            print OUT "</DL>\n";
        }
	}
    if ($type != 2) {
        print OUT "    <LI>$item\n";
    } else {
        print OUT "    <DT>$item</DT>\n";
        $g_IsDefineData = 1;
    }
}

#List Close all level
sub CloseList 
{
	while(@g_aListOrder) {
        my ($close_type) = pop(@g_aListOrder);
        if ($close_type == 0) {
            print OUT "</UL>\n";
        } elsif ($close_type == 1) {
            print OUT "</OL>\n";
        } elsif ($close_type == 2) {
            print OUT "</DL>\n";
        }
	}
	@g_aListIndent = ();
}

#code(<PRE>) 
sub DocCode 
{
    if ($UseGoogleCodePrettify) {
        print OUT "<PRE class=\"prettyprint\">\n";
    } else {
        print OUT "<PRE>\n";
    }
	while($_= &ReadSource()) {
		if ($_ =~ /^\-\-end/) {
			last;
		}
        my $text = $_;
        $text =~ s/\&/\&amp\;/g; # '&' → '&amp;'
        $text =~ s/\</\&lt\;/g;  # '<' → '&lt;'
        $text =~ s/\>/\&gt\;/g;  # '>' → '&gt;'
		print OUT $text;
	}
	print OUT "</PRE>\n";
}

#table
sub DocTable
{
	local(@row,@columeSize);
	local($h) = "";
	local($nRow) = 0;
	local($sum, $i, $percent);
	print OUT "<TABLE>\n";
	while($_ = &ReadSource()) {
		if ($_ =~ /^\-\-end/) {
			last;
		} elsif ($_ =~ /^[\-\,\ ]+$/) { #仕切り線、兼、バランス
			chop($_);
			@row = split(/\s*\,\s*/, $_);
			foreach (@row) {
				push(@columeSize, length($_));
				$sum += length($_);
			}
			next;
		}
		if ($nRow == 0) {
			$h = $_;
			$nRow ++;
			next;
		} elsif ($nRow == 1) {
			print OUT "<TR>\n";
			@row = split(/\ *\,\ */, $h);
			$i = 0;
			foreach (@row) {
				$item = &HTMLText($_);
				$percent = int($columeSize[$i++] * 100 / $sum);
				print OUT "  <TH width=\"$percent%\">$item</TH>\n";
			}
			print OUT "</TR>\n";
		}
		print OUT "<TR>\n";
		@row = split(/\ *\,\ */, $_);
		foreach (@row) {
			$item = &HTMLText($_);
			print OUT "  <TD>$item</TD>\n";
		}
		print OUT "</TR>\n";
		$nRow ++;
	}
	print OUT "</TABLE>\n";
}

sub DocTable2
{
	local(@row,@columeSize);
	local($h) = "";
	local($nRow) = 0;
	local($sum, $i, $percent);
	print OUT "<TABLE>\n";
	while($_ = &ReadSource()) {
		if ($_ =~ /^\s*$/) {                                     # 空行で終了
			last;
        } else {
            print OUT "<TR>\n";
            @row = split(/\t+/, $_);
            foreach (@row) {
                if ($_ =~ /^\[(.*)\]$/) {
                    $item = &HTMLText($1);
                    print OUT "  <TH>$item</TH>\n";
                } else {
                    $item = &HTMLText($_);
                    print OUT "  <TD>$item</TD>\n";
                }
            }
            print OUT "</TR>\n";
            $nRow ++;
        }
	}
	print OUT "</TABLE>\n";
}

# Bar
# FORMAT:
#  Lable : num PostFix
#  ex.   finished : 95.5%
sub DocBar
{
	my (@list, $max ,$i);
    $i = 0;
	while($_ = &ReadSource()) {
		if ($_ =~ /^\-\-end/) {
			last;
		} elsif ($_ =~ /\s*(.+)\s*\:\s*([\d\.]+)\s*([^\d\.]?)/) {
            if ($3 eq "%") {
                $max = 100;
            } elsif ($2 > $max) {
                $max = $2;
            }
            $list[$i++] = $_;
		}
	}
	print OUT "<TABLE border=0 cellspacing=0 cellpadding=1>\n";
    foreach $b (@list) {
        if ($b =~ /\s*(.+)\s*\:\s*([\d\.]+)(.*)/) {
            my $length = (10.0 * $2 / $max) . "em";
			print OUT "<TR>\n";
			print OUT "  <TH>$1</TH>\n";
            print OUT "  <TD align=left width=10em><div style=\"background-color: darkslateblue; width: $length; font-size: 1em;\">&nbsp;</div></TD>\n";
			print OUT "  <TD>$2$3</TD>\n";
			print OUT "</TR>\n";
        }
    }
        
	print OUT "</TABLE>\n";
}

#Sequence Chart
sub DocSequence
{
	&Sqlib::Initialize();                                        #
    my @last_objects = ();
	while($_ = &ReadSource()) {
		if ($_ =~ /^\-\-end/) {                                  # --end
			last;
		} elsif ($_ =~ /^\#(.*)$/) {                             # #Objects
			my @obj = split(/\ *\,\ */, $1);
			foreach (@obj) {
				&Sqlib::AddNode($_);
			}
		} elsif ($_ =~ /\s*(\w+)\s*\-\>\s*(\w+)\.(.*)$/) {       # o -> o.m
			&Sqlib::AddSequence($1, $2, $3, "SYNC",1);             # 同期呼出
		} elsif ($_ =~ /\s*(\w+)\s*\<\-\s*(\w+)\.(.*)$/) {       # o <- o.m
			&Sqlib::AddSequence($2, $1, $3, "RET",1);              # 戻り
		} elsif ($_ =~ /\s*(\w+)\s*\-\-\>\s*(\w+)\.(.*)$/) {     # o --> o.m
			&Sqlib::AddSequence($1, $2, $3, "ASYNC",1);            # 非同期呼出
		} elsif ($_ =~ /ENTER\s*(\w+)/) {                        # Enter o
            &Sqlib::EnterThread($1, 1);
            push(@last_objects, $1);
		} elsif ($_ =~ /EXIT\s*(\w+)/) {                         # Enter o
            &Sqlib::ExitThread($1, 1);
            pop(@last_objects);
		} elsif ($_ =~ /\s*\-\>\s*(\w+)\.(.*)$/) {       # -> o.m
            if (@last_objects) {
                &Sqlib::AddSequence($last_objects[$#last_objects],
                                    $1, $2, "SYNC",1);
            }
		} elsif ($_ =~ /\s*(\w+)\s*\<\-\s*([^.]*)$/) {       # <- o.m
            if (@last_objects) {
                &Sqlib::AddSequence($last_objects[$#last_objects], $1,
                                    $2, "RET",1);
            }
		} elsif ($_ =~ /\s*\-\-\>\s*(\w+)\.(.*)$/) {     # --> o.m
            if (@last_objects) {
                &Sqlib::AddSequence($last_objects[$#last_objects],
                                    $1, $2, "ASYNC",1);
            }
        }
	}
    my ($idFig) = &GetFigureName();
	my ($figs, $x, $y) = &Sqlib::MakeSVG("$ImageDir/Fig-$idFig.svg");
	&EmbedSVG("./$ImageDirName/Fig-$idFig.svg", $x, $y);
    &AddOutputFile("$ImageDir/Fig-$idFig.svg");
}

# Trace use xTrace
sub DocTrace
{
	&Sqlib::Initialize();                                        #
    my @last_objects = ();
    my $thread_id,$process_id;
    
	while($_ = &ReadSource()) {
        $thread_id = 1;
        $process_id = 1;
        if ($_ =~ /^\s*([0-9]+)\s*PID\:([0-9a-fA-f]*)\s*TID\:([0-9a-fA-f]*)/) {  #Time Line
            $process_id = $2;
            $thread_id = $3;
        }

		if ($_ =~ /^\-\-end/) {                                  # --end
			last;
		} elsif ($_ =~ /^\#(.*)$/) {                             # #Objects
			my @obj = split(/\ *\,\ */, $1);
			foreach (@obj) {
				&Sqlib::AddNode($_);
			}
		} elsif ($_ =~ /Trace\s*\-\s*ENTER\s*(\w+)\:\:(\w+)\s*\-\>\s*(\w+)\:\:(.*)$/) {       # ENTER c::m -> c.m(a)
			&Sqlib::AddSequence($1, $3, $4, "SYNC", $thread_id);
            &Sqlib::EnterThread($3, $thread_id);
		} elsif ($_ =~ /Trace\s*\-\s*ENTER\s*(\w+)\:\:(.*)$/) {  # ENTER c::m
			&Sqlib::AddSequence($1, $1, $2, "SYNC", $thread_id);
            &Sqlib::EnterThread($1, $thread_id);
		} elsif ($_ =~ /\s*(\w+)\s*\<\-\s*(\w+)\.(.*)$/) {       # o <- o.m
			&Sqlib::AddSequence($2, $1, $3, "RET", $thread_id);  # 戻り
		} elsif ($_ =~ /\s*(\w+)\s*\-\-\>\s*(\w+)\.(.*)$/) {     # o --> o.m
			&Sqlib::AddSequence($1, $2, $3, "ASYNC", $thread_id); # 非同期呼出
		} elsif ($_ =~ /EXIT\s*(\w+)/) {                         # Enter o
            &Sqlib::ExitThread($1, $thread_id);
        } elsif ($_ =~ /WAIT\sTHREAD/) {                         #WAIT THREAD
            &Sqlib::WaitThread($thread_id);
        } elsif ($_ =~ /RESTART\sTHREAD/) {                      #RESTART THREAD
            &Sqlib::RestartThread($thread_id);
        }
	}
    my ($idFig) = &GetFigureName();
	my ($figs, $x, $y) = &Sqlib::MakeSVG("$ImageDir/Fig-$idFig.svg");
	&EmbedSVG("./$ImageDirName/Fig-$idFig.svg", $x, $y);
    &AddOutputFile("$ImageDir/Fig-$idFig.svg");
}

#状態遷移図
sub DocState
{
    my ($to_group, $to_state, $from_group, $from_state, $event);
	&Stlib::Initialize();                                        # 
	while($_ = &ReadSource()) {
		if ($_ =~ /^\-\-end/) {
            last;
		} elsif ($_ =~ /\s*([^\s]+)\s*\-\>\s*([^\s]+)\s*(\[([^\]]*)\]|)$/) {
            # s -> s [label]
            $from_state = $1;
            $to_state = $2;
            $event = $4;
            if ($to_state =~ /(\w+)\.(.*)/) {
                $to_group = $1;
                $to_state = $2;
            } else {
                $to_group = "";
            }
            if ($from_state =~ /(\w+)\.(.*)/) {
                $from_group = $1;
                $from_state = $2;
            } else {
                $from_group = "";
            }
            &Stlib::AddTransition($from_group, $from_state,
                                  $to_group, $to_state,
                                  $event);
        } elsif ($_ =~ /\-\>\s*([\w\.]+)\s*(\[([^\]]*)\])?/) {
            # -> o [label]
            $to_state = $1;
            $event = $3;
            if ($to_state =~ /(\w+)\.(\w+)/) {
                $to_group = $1;
                $to_state = $2;
            } else {
                $to_group = "";
            }
            &Stlib::AddTransitionSeq($to_group, $to_state, $event);
        } elsif ($_ =~ /\^(\w+)\s*(\{.*\})/) {
            $to_state = $2;
            $event = $1;
            &Stlib::AddTransitionSeq("", $to_state, $event);            
        } elsif ($_ =~ /(\{.*\})/) {
            $to_state = $1;
            &Stlib::AddTransitionSeq("", $to_state, "");            
        } else {
        }
	}
    my ($idFig) = &GetFigureName();
    &Stlib::OutputDot("$ImageDir/Fig-$idFig.dot");
    system("dot -Tsvg $ImageDir/Fig-$idFig.dot -o $ImageDir/Fig-$idFig.svg") &&
        print ("Cannot Create $ImageDir/Fig-$idFig.svg\n");
    &Cllib::SvgComvartPT("$ImageDir/Fig-$idFig.svg");
    my ($w,$h) = &Cllib::GetSvgSize("$ImageDir/Fig-$idFig.svg");
	&EmbedSVG("./$ImageDirName/Fig-$idFig.svg", $w, $h);
    &AddOutputFile("$ImageDir/Fig-$idFig.dot");
    &AddOutputFile("$ImageDir/Fig-$idFig.svg");
}

#Class Chart
sub DocClass
{
	&Cllib::Initialize();
	while($_ = &ReadSource()) {
		if ($_ =~ /^\-\-end/) {
			last;
		} elsif ($_ =~ /import\s*(.*)$/) {
            &Cllib::ReadHeader(".", $1);
        } elsif ($_ =~ /^class\s+(\w+)\s*\;/) {        # 前方定義
            &Cllib::predefine($1);                                      # 
	    } elsif ($_ =~ /^class\s+(\w+)([^\{]*)\{(.*)$/) {     # クラス定義開始
            $Debug && printf("Add Class $1\n");
            $curClass = $1;
            $curMethod = "";
            $curProperty = "";
            my $inherit = $2;
            $streo_type = "";
            if ($3 =~ /\<\<([^\>]*)\>\>/) {
                $streo_type = $1;
            }
            $inherit =~ s/[\:\{\s]//g;
            if ($inherit) {
                foreach (split(/\,/,$inherit)) {
                    my $super;
                    $super = $_ ;
                    $super =~ s/^public\s*//g;
                    $super =~ s/^private\s*//g;
                    $super =~ s/^protected\s*//g;
                    &Cllib::AddRef($super, $curClass, "is a");
                }
            }
	    } elsif ($_ =~ /^\}\;/) {                                # Class End
            $Debug && print "Define $curClass\n";
            &Cllib::define($curClass, $curMethod, $curProperty, $streo_type);
            $curClass = "";
            $curMethod = "";
            $curProperty = "";
	    } elsif ($_ =~ /^\s+([\<\>\w]+)(.*)\/\/\s*\<\<(.*)\>\>/) { # 特徴点
            my ($type) = $1;
            my ($sep) = $2;
            my ($streo_type) = $3;
            $Debug && print " - AddRef $type, $sep, $streo_type,$curClass\n";
            if ($curClass ne "") {
                unless (&Cllib::IsClass($type)) {
                    &Cllib::predefine($type);
                }
                &Cllib::AddRef($curClass, $type, $streo_type);
            }
        } elsif ($_ =~ /([a-zA-Z_]+)\(/) {                       #method
            $curMethod .= "$1()\\l";
        } elsif ($_ =~ /^\s*([a-zA-Z_].+)\;/) {                  #property
            $curProperty .= "$1\\l";
        }
	}
    #use GraphViz 
    my ($idFig) = &GetFigureName();
    &Cllib::OutputDot("$ImageDir/Fig-$idFig.dot");
    system("dot -Tsvg $ImageDir/Fig-$idFig.dot -o $ImageDir/Fig-$idFig.svg");
    &Cllib::SvgComvartPT("$ImageDir/Fig-$idFig.svg");
    my ($w,$h) = &Cllib::GetSvgSize("$ImageDir/Fig-$idFig.svg");
	&EmbedSVG("./$ImageDirName/Fig-$idFig.svg", $w, $h);
    &AddOutputFile("$ImageDir/Fig-$idFig.dot");
    &AddOutputFile("$ImageDir/Fig-$idFig.svg");
}

#Dump
sub DocDump
{
	&dumplib::Initialize();
	while($_ = &ReadSource()) {
		if ($_ =~ /^\-\-end/) {
			last;
		} elsif ($_ =~ /\{.*\}/) {
            &dumplib::AddObject($_);
        }
	}
    #use GraphViz 
    my ($idFig) = &GetFigureName();
    &dumplib::OutputDot("$ImageDir/Fig-$idFig.dot");
#    system("dot -Tpng $ImageDir/Fig-$idFig.dot -o $ImageDir/Fig-$idFig.png");
    system("dot -Tsvg $ImageDir/Fig-$idFig.dot -o $ImageDir/Fig-$idFig.svg");
    &Cllib::SvgComvartPT("$ImageDir/Fig-$idFig.svg");
    my ($w,$h) = &Cllib::GetSvgSize("$ImageDir/Fig-$idFig.svg");
	&EmbedSVG("./$ImageDirName/Fig-$idFig.svg", $w, $h);
    &AddOutputFile("$ImageDir/Fig-$idFig.dot");
    &AddOutputFile("$ImageDir/Fig-$idFig.svg");
}

#初期化
sub InitializeDoc 
{
	%g_DocProperty = ();
	$g_DocProperty{"TITLE"} = "Untitled";
	$g_DocProperty{"UUID"} = "None";
    @g_DocOutFiles = ();                                    # Output files
	@g_aListIndent = ();
	@g_aListOrder = ();
    $g_IsDefineData = 0;                                    # 定義リストの定義部かどうか？
    $g_flagAddUuid = 1;                                     # uuidを生成したか？
}

#HTMLの特殊文字変換
sub HTMLText {
    my ($text) =@_;
    $text =~ s/\&/\&amp\;/g; # '&' → '&amp;'
    $text =~ s/\</\&lt\;/g;  # '<' → '&lt;'
    $text =~ s/\>/\&gt\;/g;  # '>' → '&gt;'
#    $text =~ s/ /\&nbsp\;/g; # ' ' → '&nbsp;'
    #特殊な展開
    $text =~ s/\&lt\;\&lt\;(.*)\&gt\;\&gt\;/\<B\>$1\<\/B\>/g;    # << >> <B>
    $text =~ s/__(.*)__/\<U\>$1\<\/U\>/g;                        # __ __ <U>
    $text =~ s/\'\'(.*)\'\'/\<I\>$1\<\/I\>/g;                    # '' '' <I>
    
    #内部リンク
    while ( $text =~ /\[\[(.*)\]\]/ ) {                # [[keyword]]
        my ($keyword) = $1;
        my ($link) = &MakeLink($keyword);
        $text =~ s/\[\[.*\]\]/$link/;
    }

	$text =~ s/\s*$//;
    return ($text);
}

sub MakeLine {
    my ($keyword) = @_;
    my ($link);
        
    return $link;
}


# Paragarph
sub EnterParagraph {
    $Paragarph = "";
}

sub AddParagraph {
    my ($line) = @_;
    $Paragarph .= &HTMLText($line);
    $Paragarph .= "\n";
}

sub AddParagraphRaw {
    my ($line) = @_;
    $Paragarph .= $line;
    $Paragarph .= "\n";
}

sub ExitParagraph {
    if ($Paragarph) {
        if ($g_IsDefineData) {
            print OUT "<DD>\n$Paragarph</DD>\n";
        } else {
            print OUT "<P>\n$Paragarph</P>\n";
        }
    }
    $Paragarph = "";
    $g_IsDefineData = 0;
}

#■Link
# referrence [[ID]]
# target: File,Heading
sub MakeLink {
    my ($keyword) = @_;
    my ($URL) = "./link/$keyword.html";
    return "<A HREF=\"$URL\">$keyword<A>";
}

#リンク先追加
sub MakeLinkTarget { 
    my ($keyword, $file, $target, $category, $timeStamp) = @_; 
    my ($item) = $g_LinkTarget{$keyword};
    my ($key) = "$file,$target,";

    if ($item && $item !~ /^$key[^;]*$/) {      # undefined
        if ($item =~ /$key/) {     #if not exist key 
            $item =~ s/$key([^;]*)/$key$category\,$timeStamp/;
            $g_LinkTarget{$keyword} = $item;
        } else {
            $g_LinkTarget{$keyword} = $g_LinkTarget{$keyword} . 
                ";$file,$target,$category,$timeStamp";            
        }
        &MakeLinkTargetSelector($keyword);
        warn("WARN:$keyword is conflict!\n");
    } else {
        $g_LinkTarget{$keyword} = 
            "$file,$target,$category,$timeStamp";
        &MakeLinkTargetSingle($keyword,$file,$target);
    }
}

#単一リンク（自動でジャンプ）
sub MakeLinkTargetSingle {
    my ($keyword,$file,$target) = @_;
    
    open(LINK, ">:utf8", "$DocDir/link/$keyword.html") || die "Can't create link file";
    my ($url);
    if ($target) {
        $url = "../$file\#$target";
    } else {
        $url = "../$file";
    }

    print LINK <<END_OF_DATA;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<HTML lang="ja">
<HEAD>
<meta http-equiv="Refresh" content="0; url=$url">
</HEAD>
</HTML>    
END_OF_DATA
    close(LINK);
}

#複数リンク（ユーザに選択させる）
sub MakeLinkTargetSelector {
    my ($keyword) = @_;
    my (@targets) = split(/;/,$g_LinkTarget{$keyword});
    my ($item);
    my ($links) = "";
    
    foreach $item (@targets) {
        my ($file,$target,$category,$timeStamp) =  split(/\,/,$item);
        
        if ($file) {
            $links = $links . "    " .
                "    <li><A HREF=\"../$file\">$category / $keyword</A> update $timeStamp</li>\n";
        } else {
            $links = $links . 
                "    <li><A HREF=\"../$file#$target\">$category / $keyword</A> update $timeStamp</li>\n";
        }
    }

    open(LINK, "> $DocDir/link/$keyword.html") || die "Can't create link file";
    print LINK <<END_OF_DATA;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<HTML lang="ja">
<HEAD>
  <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <LINK rel="stylesheet" href="../DocStyle.css">
  <TITLE>Select Link</TITLE>
</HEAD>
<BODY>

<ul class="SelectLink"> 
    $links
</ul> 

</BODY>
</HTML>
END_OF_DATA
    close(LINK);
}

# load .link file 
#添付ファイル 
sub IsAttachFile {
    my ($name) = @_;
    if ($name =~ /\.([a-zA-Z]+)$/) {
        my ($ext) = $1;
        $ext =~ s/(\w*)/\L$1/g;      #change small latter
        if ($AttachExt{$ext}) {
            return $AttachExt{$ext};
        }
    }
    return 0;
}

sub MakeAttachFile {
    my ($name) = @_;
    my ($type) = &IsAttachFile($name);
    if ($type == 1) {
        &MakeImage("./Attach/$name");
    } elsif ($type = 2) {
        my ($keyword) = @_;
        my ($URL) = "./Attach/$name";
        printf OUT "<A HREF=\"$URL\">$name<A>"; 
    }
}

# ===
#  ■永続化情報を保存/読み込みする部分
#    package Storableを使いドキュメントの情報を保存する．
#    対象変数は以下の通り
#
#  **table
#  [変数]               [格納情報]
#  @g_DocDB             Index情報
#  %g_LinkTarget        Link情報
#  %g_Documents         ファイルの情報
# ===

#Save 
sub SaveDocDB {
    $Debug && print "save - .docdb\n";
    nstore [ \@g_DocDB, \%g_LinkTarget, \%g_Documents ], "$DocDir/.docdb";
}

#Load
sub LoadDocDB {
    if (-e "$DocDir/.docdb") {
        my ($data) = retrieve "$DocDir/.docdb";
        my ($ref);

        $ref = $data->[0];
        @g_DocDB = @$ref;
        $ref = $data->[1];
        %g_LinkTarget  = %$ref;
        $ref = $data->[2];
        %g_Documents = %$ref;
        
        $Debug && print "load - .docdb\n";
        $Debug && print "     - .docdb docdb\n";
        $Debug && print Dumper(@g_DocDB);
        $Debug && print "     - .docdb link\n";
        $Debug && print Dumper(%g_LinkTarget);
        $Debug && print "     - .docdb document data\n";
        $Debug && print Dumper(%g_Documents);
    } else {
        $Debug && print " - no .docdb\n";

        @g_DocDB = ();
        %g_LinkTarget = ();                                 # Link情報
        %g_Documents = ();                                  # Index情報
    }
}


# ドキュメントを削除する
# 対象ドキュメントの出力ファイルをファイルシステム上削除
# 各種情報（Index,Link)のクリア
sub DeleteDoc {
    my ($uuid) = @_;
    my ($ref)  = $g_Documents{$uuid}[5];
    my (@outfiles)  = @$ref;
    my ($path) = $g_Documents{$uuid}[3];
    my ($file);
    $Debug && print "Delete Document $path\n";
    
    foreach $file (@outfiles) {
        $Debug && print "remove $file\n";
        if ($file ne "$DocDir/$OutFile") {
            unlink ( $file ) || print "cannot remove $file ... $!\n";
        }
    }
    my @newDocDB = ();
    foreach $docdb (@g_DocDB) {
        if ($docdb->[3] ne $path) {
            push(@newDocDB, $docdb);
        } else {
            $Debug && print "remove docdb \n";
            $Debug && print Dumper($docdb);
        }
    }
    @g_DocDB = @newDocDB;

    my $name,$value,$item, $new_value;
    while (($name, $value) = each(%g_LinkTarget)) {
        my (@targets) = split(/;/,$value);
        $new_value = 0;
        foreach $item (@targets) {
            my ($file,$target,$category,$timeStamp) =  split(/\,/,$item);
            if ($file ne $path) {
                if ($new_value) {
                    $new_value = $new_value . ";" . $item;
                } else {
                    $new_value = $item;
                }
            } else {
                $Debug && print "remove link $item\n";
            }
        }
        $g_LinkTarget{$name} = $new_value;
    }
}


#図表名称(UUID)
sub GetFigureName {
    my($ug)    = new Data::UUID;
    $uuid = $ug->create_str();
    return $uuid;
}

# ===
# ■ファイル読み込み部
#  + 通常のテキスト(.txt)の場合，普通に読み込む．
#  + ソース(.cpp .h .pl)などのコメント部分のみを読み込む．
#  + 基本開始記号$FsdBlockSep("===")の範囲を読み込む．
#    - OpenSource/CloseSource関数でファイルを開く/閉じる．
#    - ReadSource関数で一行取得(不要部分削除)
#
#  TODO:ソースの前後のソースを別変数に格納するようにして，関数仕様書や
#       クラス仕様書を作れるようにしたい
# ===
sub OpenSource {
    my ($name) = @_;
    
    open(FILE, $name) || die "Can't open to $name";         # ファイルを開く
    if ($name =~ /\.[Cc][Pp][Pp]$/) {                       # 拡張子.cpp
        $SourceLanguage = "CPP";
    } elsif ($name =~ /\.[Cc]$/) {                          # 拡張子.c
        $SourceLanguage = "CPP";
    } elsif ($name =~ /\.[Hh]$/) {                          # 拡張子.h
        $SourceLanguage = "CPP";
    } elsif ($name =~ /\.[Pp][Ll]$/) {                      # 拡張子.pl
        $SourceLanguage = "PL";
    } else {                                                # 他
        $SourceLanguage = "TXT";                               
    }
    #initialize buffer
    $IsInFsdMarker = 0;
    $PreviousCodes = "";
    $AfterCodes = "";
}

sub CloseSource {
    close(FILE);
}

sub ReadSource {
    my($line);
    if (eof(FILE)) {
        return 0;
    }
    if ($SourceLanguage eq "TXT") {
        $line = Encode::decode($InCodingSystem{$SourceLanguage},<FILE>);
        return $line;
    } elsif ($SourceLanguage eq "CPP") {
        # TODO : コメント抽出
        while (!eof(FILE)) {
            $line = Encode::decode($InCodingSystem{$SourceLanguage},<FILE>);
            if ($IsInCComment) {
                if ($line =~ /^(.*[^\*])\*+\//) {                     # */
                    $IsInCComment = 0;
                    $line = "$1\n";
                } 
            } else {
                if ($line =~ /\/\*+([^\*]*.)$/) {                    # /*
                    $IsInCComment = 1;
                    $line = "$1\n";
                } elsif ($line =~ /\/\/+([^\/]*.)$/) {               # //
                    $line = "$1\n";
                } else {                                    # コード行
                    $IsInFsdMarker = 0;                     # 
                    next;                                   # 読み飛ばし
                }
            }
            # marker中かどうか
            if ($line =~ /^\s*$FsdBlockSep/) {          # Marker
                $IsInFsdMarker =  ! $IsInFsdMarker;
                return "\n";                            # return null line
            } else {
                if ($IsInFsdMarker) {
                    return "$line";
                } 
            }
        }
        return 0;
    } elsif ($SourceLanguage eq "PL") {
        while (! eof(FILE)) {
            $line = Encode::decode($InCodingSystem{$SourceLanguage},<FILE>);
            # コメント以外を読み飛ばし            
            if  ($line !~ /\#/) {                 
                $IsInFsdMarker = 0;
                next;
            }
            $line =~ s/^.*\#+//;
            # marker中かどうか
            if ($line =~ /^\s*$FsdBlockSep/) {                  # Marker
                $IsInFsdMarker =  ! $IsInFsdMarker;
                return "\n";                                # return null line
            } else {
                if ($IsInFsdMarker) {
                    return "$line";
                } 
            }
        }                                                   # while
        return 0;                                           # if eof
    }
}

